package com.atguigu.tingshu.common.login;

import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserInfo;
import io.micrometer.common.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;

/**
 * projectName: com.atguigu.tingshu.common.login
 *
 * @author: 杨天伦
 * description:
 * time: 2025/6/26 14:26
 */
@Aspect
@Component
@Slf4j
public class TsLoginAspect {

    @Autowired
    RedisTemplate redisTemplate;

    @Around("@annotation(tsLogin)")
    public Object around(ProceedingJoinPoint joinPoint, TsLogin tsLogin) throws Throwable {
        //登录拦截功能

        /**
         * 登录业务：1.当成功成功之后，会将token写入请求头；判断请求头中是否有token;
         *          2.校验成功之后，会将用户信息存储到缓存!
         */
        // 1.应该先获取到请求对象，然后在从头中拿token
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String token = request.getHeader("token");
        //考虑如何获取到注解的属性
//        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//        TsLogin annotation = signature.getMethod().getAnnotation(TsLogin.class);
//        boolean required = annotation.required();
        boolean required = tsLogin.required();

        //判断
        if (required) {
            //需要登录
            if (StringUtils.isEmpty(token)) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //获取缓存信息，看缓存中是否真正有用户信息
            String key = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(key);

            if (null == userInfo) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
        }
        //判断token不为空
        if (!StringUtils.isEmpty(token)) {
            //获取缓存数据
            String key = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(key);
            if (null != userInfo) {
                //userInfo.getId()
                AuthContextHolder.setUserId(userInfo.getId());
                AuthContextHolder.setUsername(userInfo.getNickname());
            }
        }
        Object proceed = null;
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable e) {
            log.error(e.getMessage(), e);
        } finally {
            //删除防止内存泄漏OOM异常
            AuthContextHolder.removeUserId();
            AuthContextHolder.removeUsername();
        }
        return proceed;//进去执行方法体(执行的是拦截控制器的方法体)
    }
}
